package com.mh.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.nativepay.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Date;

/**
 * Date:2023/9/8
 * author:zmh
 * description: Native支付相关
 **/

@Component
@Slf4j
public class NativeUtil {

    /** 商户号 */
    @Value("${wxPay.jsApi.mchId}")
    private String merchantId;

    /** 商户API私钥路径 */
    @Value("${wxPay.priKey}")
    private String privateKeyPath;

    /** 商户证书序列号 */
    @Value("${wxPay.jsApi.mchSerialNo}")
    private String merchantSerialNumber;

    /** 商户APIV3密钥 */
    @Value("${wxPay.jsApi.apiV3Key}")
    private String apiV3Key;

    @Value("${wxPay.appId}")
    private String appId;

    /**
     * Native支付下单，获取支付地址
     * @param total 金额
     * @return 支付地址，前端用于生成支付二维码
     */
    public String nativePay(Integer total){
        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(NativeUtil.getResourcesPath() + "apiclient_key.pem")
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3Key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(total);
        request.setAmount(amount);
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setDescription("Native测试商品标题");
        request.setNotifyUrl("http://139.159.151.0:8080/pay/notifyNative");
        // 生成模拟系统内部订单号（yyyyMMddHHmmssSSS）
        request.setOutTradeNo(DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN));
        // 调用下单方法，得到应答
        try {
            PrepayResponse response = service.prepay(request);
            // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
            System.out.println(response.getCodeUrl());
            return response.getCodeUrl();
        }catch (Exception e){
            System.out.println(e.getMessage());
            return e.getMessage();
        }
    }

    /**
     * 获取证书路径
     * @return ·
     */
    public static String getResourcesPath() {
        // 这里需要注意的是ApplicationHome是属于SpringBoot的类
        // 获取项目下resources/static/img路径
        // 需要注意的是：此处的applicationHome是打包后的路径，也就是classes目录
        ApplicationHome applicationHome = new ApplicationHome(NativeUtil.class);

        // 保存目录位置根据项目需求可随意更改 - win和linux目录不一样
//        String path = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() + "/src/main/resources/pay/";
//        String path = applicationHome.getDir() + "/pay/";
        String path = applicationHome.getDir() + "/";
        System.out.println("path:" + path);
        return path;
    }

    /**
     * 成功支付的回调
     * @param request ·
     * @param response ·
     * @throws IOException ·
     */
    public void notifyNative(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // 获取请求体原内容（此时获取的数据是加密的）
        BufferedReader reader = request.getReader();
        StringBuilder requestBody = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            requestBody.append(line);
        }

        // 获取请求携带的数据，构造参数
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial")) // 微信支付平台证书的序列号
                .nonce(request.getHeader("Wechatpay-Nonce")) // 签名中的随机数
                .signature(request.getHeader("Wechatpay-Signature"))  // 应答的微信支付签名
                .timestamp(request.getHeader("Wechatpay-Timestamp")) // 签名中的时间戳
                .body(requestBody.toString()) // 请求体内容（原始内容，不要解析）
                .build();

        // 初始化RSAAutoCertificateConfig
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId) // 商户号
                // API证书路径，路径自己调试，能找到就行（NativeUtil为自定义工具类）
                .privateKeyFromPath(NativeUtil.getResourcesPath() + "apiclient_key.pem")
                .merchantSerialNumber(merchantSerialNumber) // 证书序列号
                .apiV3Key(apiV3Key) // APIV3密匙
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        // 解析为Transaction对象（解密数据）
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        // 获取支付单号
        log.info("支付成功，回调信息：{}", transaction);
        log.info("微信支付单号：{}", transaction.getTransactionId());
    }

}
